﻿#region Copyright 
/*-------------------------------------------------------------------------
* 命名空间名称/文件名:    SSPivot.Common.Helpers/EncryptHelper 
* CLR版本:     4.0.30319.42000
* 机器名称:    DESKTOP-NHMLO8A
* 功 能：       N/A
* 类 名：       EncryptHelper
* 创建时间：  2025/6/3 17:50:59
* 版本号：      v1.0
* 创建人:        xulong
*-------------------------------------------------------------------------*/
#endregion

using Org.BouncyCastle.Utilities.Encoders;
using SSPivot.Common.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks; 

namespace SSPivot.Common.Helpers
{
    /// <summary>
    /// 加密解密
    /// </summary>
    public class EncryptHelper
    {
        #region AES加密    
        
        // <summary>
        /// AES ECB模式加密并返回十六进制字符串（与Python pycryptodome兼容）
        /// </summary>
        /// <param name="content">要加密的文本</param>
        /// <param name="aesKey">UTF-8编码的密钥字符串</param>
        /// <returns>加密后的十六进制字符串</returns>
        public static string AesEcbEncryptToHex(string content, string aesKey, string iv = "")
        {
            // 将密钥字符串转换为字节数组
            byte[] keyBytes = Encoding.UTF8.GetBytes(aesKey);

            // 验证密钥长度
            if (keyBytes.Length != 16 && keyBytes.Length != 24 && keyBytes.Length != 32)
                throw new ArgumentException("密钥长度必须为16、24或32字节");

            // 使用AES实例
            using Aes aes = Aes.Create();
            aes.Key = keyBytes;
            aes.Mode = CipherMode.ECB;           // ECB模式
            aes.Padding = PaddingMode.PKCS7;      // PKCS7填充
            if (string.IsNullOrEmpty(iv))
            {
                aes.IV = new byte[16]; // ECB模式不需要IV，但必须设置 
            }
            else
            {
                aes.IV = Encoding.UTF8.GetBytes(iv);
            }
                    

            // 创建加密器并执行加密
            using ICryptoTransform encryptor = aes.CreateEncryptor();
            byte[] plainBytes = Encoding.UTF8.GetBytes(content);

            // 重要：使用MemoryStream确保正确填充
            using MemoryStream ms = new MemoryStream();
            using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
            {
                cs.Write(plainBytes, 0, plainBytes.Length);
                // 确保所有数据刷新到内存流
                cs.FlushFinalBlock();
            }
            byte[] encryptedBytes = ms.ToArray();

            // 转换为十六进制字符串（小写）
            return BitConverter.ToString(encryptedBytes).Replace("-", "").ToLower();
        }
        /// <summary>
        /// 通过16进制反解内容
        /// </summary>
        /// <param name="hexCiphertext"></param>
        /// <param name="aesKey"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static string AesEcbDecryptFromHex(string hexCiphertext, string aesKey, string iv = "")
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(aesKey);
            byte[] cipherBytes = Convert.FromHexString(hexCiphertext);

            using Aes aes = Aes.Create();
            aes.Key = keyBytes;
            aes.Mode = CipherMode.ECB;
            aes.Padding = PaddingMode.PKCS7;
            if (string.IsNullOrEmpty(iv))
            {
                aes.IV = new byte[16]; // ECB模式不需要IV，但必须设置 
            }
            else
            {
                aes.IV = Encoding.UTF8.GetBytes(iv);
            }
             
            using ICryptoTransform decryptor = aes.CreateDecryptor();
            byte[] decryptedBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length);
            return Encoding.UTF8.GetString(decryptedBytes);
        }
        #endregion

        #region base64
        /// <summary>
        /// Base64加密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string Base64Encode(string source, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            try
            {
                return Convert.ToBase64String(encoding.GetBytes(source));
            }
            catch
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// Base64解密
        /// </summary>
        /// <param name="srouce"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string Base64Decode(string srouce, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            try
            {
                return encoding.GetString(Convert.FromBase64String(srouce));
            }
            catch
            {
                return string.Empty;
            }
        }
        #endregion

        #region hash
        /// <summary>
        /// 获取哈希之后的字符串
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="str">源字符串</param>
        /// <returns>哈希算法处理之后的字符串</returns>
        public static string GetHashedString(HashType type, string str) => GetHashedString(type, str, Encoding.UTF8);

        /// <summary>
        /// 获取哈希之后的字符串
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="str">源字符串</param>
        /// <param name="isLower">是否是小写</param>
        /// <returns>哈希算法处理之后的字符串</returns>
        public static string GetHashedString(HashType type, string str, bool isLower) => GetHashedString(type, str, Encoding.UTF8, isLower);

        /// <summary>
        /// 获取哈希之后的字符串
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="str">源字符串</param>
        /// <param name="key">key</param>
        /// <param name="isLower">是否是小写</param>
        /// <returns>哈希算法处理之后的字符串</returns>
        public static string GetHashedString(HashType type, string str, string key, bool isLower = false) => GetHashedString(type, str, key, Encoding.UTF8, isLower);

        /// <summary>
        /// 获取哈希之后的字符串
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="str">源字符串</param>
        /// <param name="encoding">编码类型</param>
        /// <param name="isLower">是否是小写</param>
        /// <returns>哈希算法处理之后的字符串</returns>
        public static string GetHashedString(HashType type, string str, Encoding encoding, bool isLower = false) => GetHashedString(type, str, null, encoding, isLower);

        /// <summary>
        /// 获取哈希之后的字符串
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="str">源字符串</param>
        /// <param name="key">key</param>
        /// <param name="encoding">编码类型</param>
        /// <param name="isLower">是否是小写</param>
        /// <returns>哈希算法处理之后的字符串</returns>
        public static string GetHashedString(HashType type, string str, string key, Encoding encoding, bool isLower = false)
        {
            return string.IsNullOrEmpty(str) ? string.Empty : GetHashedString(type, str.ToByteArray(encoding), string.IsNullOrEmpty(key) ? null : encoding.GetBytes(key), isLower);
        }

        /// <summary>
        /// 计算字符串Hash值
        /// </summary>
        /// <param name="type">hash类型</param>
        /// <param name="source">source</param>
        /// <returns>hash过的字节数组</returns>
        public static string GetHashedString(HashType type, byte[] source) => GetHashedString(type, source, null);

        /// <summary>
        /// 计算字符串Hash值
        /// </summary>
        /// <param name="type">hash类型</param>
        /// <param name="source">source</param>
        /// <param name="isLower">isLower</param>
        /// <returns>hash过的字节数组</returns>
        public static string GetHashedString(HashType type, byte[] source, bool isLower) => GetHashedString(type, source, null, isLower);

        /// <summary>
        /// 获取哈希之后的字符串
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="source">源</param>
        /// <param name="key">key</param>
        /// <param name="isLower">是否是小写</param>
        /// <returns>哈希算法处理之后的字符串</returns>
        public static string GetHashedString(HashType type, byte[] source, byte[] key, bool isLower = false)
        {
            if (null == source)
            {
                return string.Empty;
            }
            var hashedBytes = GetHashedBytes(type, source, key.IsNotNullOrEmpty() ? key : null);
            var sbText = new StringBuilder();
            if (isLower)
            {
                foreach (var b in hashedBytes)
                {
                    sbText.Append(b.ToString("x2"));
                }
            }
            else
            {
                foreach (var b in hashedBytes)
                {
                    sbText.Append(b.ToString("X2"));
                }
            }
            return sbText.ToString();
        }

        /// <summary>
        /// 计算字符串Hash值
        /// </summary>
        /// <param name="type">hash类型</param>
        /// <param name="str">要hash的字符串</param>
        /// <returns>hash过的字节数组</returns>
        public static byte[] GetHashedBytes(HashType type, string str) => GetHashedBytes(type, str, Encoding.UTF8);

        /// <summary>
        /// 计算字符串Hash值
        /// </summary>
        /// <param name="type">hash类型</param>
        /// <param name="str">要hash的字符串</param>
        /// <param name="encoding">编码类型</param>
        /// <returns>hash过的字节数组</returns>
        public static byte[] GetHashedBytes(HashType type, string str, Encoding encoding)
        {
            if (null == str)
            {
                return null;
            }
            var bytes = encoding.GetBytes(str);
            return GetHashedBytes(type, bytes);
        }

        /// <summary>
        /// 获取Hash后的字节数组
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="bytes">原字节数组</param>
        /// <returns></returns>
        public static byte[] GetHashedBytes(HashType type, byte[] bytes) => GetHashedBytes(type, bytes, null);

        /// <summary>
        /// 获取Hash后的字节数组
        /// </summary>
        /// <param name="type">哈希类型</param>
        /// <param name="key">key</param>
        /// <param name="bytes">原字节数组</param>
        /// <returns></returns>
        public static byte[] GetHashedBytes(HashType type, byte[] bytes, byte[] key)
        {
            if (null == bytes)
            {
                return bytes;
            }

            HashAlgorithm algorithm = null;
            try
            {
                if (key == null)
                {
                    switch (type)
                    {
                        case HashType.MD5:
                            algorithm = MD5.Create();
                            break;

                        case HashType.SHA1:
                            algorithm = SHA1.Create();
                            break;

                        case HashType.SHA256:
                            algorithm = SHA256.Create();
                            break;

                        case HashType.SHA384:
                            algorithm = SHA384.Create();
                            break;

                        case HashType.SHA512:
                            algorithm = SHA512.Create();
                            break;

                        default:
                            algorithm = MD5.Create();
                            break;
                    }
                }
                else
                {
                    switch (type)
                    {
                        case HashType.MD5:
                            algorithm = new HMACMD5(key);
                            break;

                        case HashType.SHA1:
                            algorithm = new HMACSHA1(key);
                            break;

                        case HashType.SHA256:
                            algorithm = new HMACSHA256(key);
                            break;

                        case HashType.SHA384:
                            algorithm = new HMACSHA384(key);
                            break;

                        case HashType.SHA512:
                            algorithm = new HMACSHA512(key);
                            break;

                        default:
                            algorithm = new HMACMD5(key);
                            break;
                    }
                }
                return algorithm.ComputeHash(bytes);
            }
            finally
            {
                algorithm?.Dispose();
            }
        }

        #endregion

        #region md5

        /// <summary>
        /// 可以反解的Md5加密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="encryptKey"></param>
        /// <returns></returns>
        public static string MD5Encrypt(string source, string encryptKey)
        {
            TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
            MD5CryptoServiceProvider hashMD5 = new MD5CryptoServiceProvider();

            byte[] inputByteArray = Encoding.UTF8.GetBytes(source);
            //des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
            des.Key = hashMD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(encryptKey));
            des.Mode = CipherMode.ECB;
            //des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            StringBuilder ret = new StringBuilder();
            foreach (byte b in ms.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }
            return ret.ToString();

        }

        /// <summary>
        /// 可以反解的Md5解密
        /// </summary>
        /// <param name="source"></param>
        /// <param name="decryptKey"></param>
        /// <returns></returns>
        public static string MD5Decrypt(string source, string decryptKey)
        {
            TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider();
            MD5CryptoServiceProvider hashMD5 = new MD5CryptoServiceProvider();
            try
            {
                byte[] inputByteArray = new byte[source.Length / 2];
                for (int x = 0; x < source.Length / 2; x++)
                {
                    int i = (Convert.ToInt32(source.Substring(x * 2, 2), 16));
                    inputByteArray[x] = (byte)i;
                }

                //des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
                des.Key = hashMD5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(decryptKey));
                des.Mode = CipherMode.ECB;
                //des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
                MemoryStream ms = new MemoryStream();
                CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
                cs.Write(inputByteArray, 0, inputByteArray.Length);
                cs.FlushFinalBlock();
                return Encoding.UTF8.GetString(ms.ToArray());
            }
            catch
            {
                return string.Empty;
            }
        }

        #endregion

        #region rsa
        /// <summary>
        /// SHA256函数
        /// </summary>
        /// <param name="source">原始字符串</param>
        /// <param name="encoding">编码格式</param>
        /// <returns>SHA256结果</returns>
        public static string SHA256Encode(string source, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            using (var sha256 = System.Security.Cryptography.SHA256.Create())
            {
                var shah = sha256.ComputeHash(encoding.GetBytes(source));
                return BitConverter.ToString(shah).Replace("-", "").ToLower();
            }
        }
        /// <summary>
        /// HMAC_SHA256 签名
        /// </summary>
        /// <param name="source"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string HMAC_SHA256(string source, string key, Encoding encoding = null)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            using (var hmacSha256 = new HMACSHA256(encoding.GetBytes(key)))
            {
                var shah = hmacSha256.ComputeHash(encoding.GetBytes(source));
                return BitConverter.ToString(shah).Replace("-", "").ToLower();
            }
        }
        /// <summary>
        /// SHA256 转换为 Hex字符串
        /// </summary>
        /// <param name="data"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static string SHA256Hex(string data, Encoding encoding = null,bool toLowerCase=true)
        {
            if (encoding == null) encoding = Encoding.UTF8;
            var bytes = encoding.GetBytes(data);
            using (var sha256 = SHA256.Create())
            {
                var hash = sha256.ComputeHash(bytes);
                var hex = BitConverter.ToString(hash).Replace("-", string.Empty);
                return toLowerCase ? hex.ToLower() : hex.ToUpper(); 
            }
        }
        /// <summary>
        /// SHA256 转换为 Hex字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string Sha256Hex(byte[] bytes, bool toLowerCase = true)
        {
            using (var sha256 = SHA256.Create())
            {
                var hash = sha256.ComputeHash(bytes);
                var hex = BitConverter.ToString(hash).Replace("-", string.Empty);
                return toLowerCase ? hex.ToLower() : hex.ToUpper(); 
            }
        }
        /// <summary>
        /// Sha256加密
        /// </summary>
        /// <param name="str">要加密的字符串</param>
        /// <returns>加密后的十六进制的哈希散列（字符串）</returns>
        public static string Sha256(string str, string format = "x2")
        {
            var buffer = Encoding.UTF8.GetBytes(str);
            var data = SHA256.Create().ComputeHash(buffer);
            var sb = new StringBuilder();
            foreach (var t in data)
            {
                sb.Append(t.ToString(format));
            }
            return sb.ToString();
        }
        #endregion
    }
}
